package com.robaone.html;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;

import org.htmlcleaner.CleanerProperties;
import org.htmlcleaner.ContentToken;
import org.htmlcleaner.EndTagToken;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.TagNode;

import com.robaone.util.Strmanip;

public class WidgetGenerator {
	@SuppressWarnings("unchecked")
	HashMap statevariables = new HashMap();
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		WidgetGenerator gen = new WidgetGenerator();
		try{
			gen.processArguments(args);
			gen.generateClass();
		}catch(Exception e){
			System.out.println("Error: "+e.getMessage());
			gen.showUsage();
			e.printStackTrace();
		}
	}

	private File m_destination_folder;
	private String m_package;
	private String m_classname;
	private File m_source_file;
	private int m_itemcounter;

	private void generateClass() throws IOException {
		HtmlCleaner cleaner = new HtmlCleaner();
		CleanerProperties props = cleaner.getProperties();
		props.setUseCdataForScriptAndStyle(true);
		props.setRecognizeUnicodeChars(true);
		props.setUseEmptyElementTags(true);
		props.setAdvancedXmlEscape(true);
		props.setTranslateSpecialEntities(true);
		props.setBooleanAttributeValues("empty");
		String html = this.getHTMLSRC();
		TagNode node = cleaner.clean(html);
		this.printNodes(node,0);

	}

	private String printNodes(TagNode node,int indent) throws IOException{
		if(node.getName().equals("body")){
			WidgetDescription compositeui = this.processElements(node, null);
			String class_src = compositeui.buildClass(this.m_classname);
			System.out.println("\n=============== The Class Source ===============");
			System.out.println("package "+this.m_package+";\n");
			System.out.println(class_src);

			class_src = "package "+this.m_package+";\n" + class_src;
			this.m_destination_folder.mkdirs();
			File output = new File(this.m_destination_folder.getAbsolutePath()+System.getProperty("file.separator")+this.m_classname+".java");
			FileWriter fw = new FileWriter(output);
			fw.write(class_src);
			fw.close();

			/*
            File element = new File(this.m_destination_folder.getAbsoluteFile()+System.getProperty("file.separator")+"HTMLElement.java");
            fw = new FileWriter(element);
            fw.write(this.getElementClassSrc());
            fw.close();
			 */
			return null;
		}
		String str = "";
		for(int i = 0; i < indent;i++){
			str += " ";
		}
		System.out.println(str+"Node = "+node.getName());
		System.out.println(str+"Attributes = "+node.getAttributes());
		System.out.println(str+"Children:");
		for(int i = 0;i < node.getChildren().size();i++){
			Object o = node.getChildren().get(i);
			if(o instanceof TagNode){
				TagNode child = (TagNode)o;
				this.printNodes(child, indent+2);
			}else if(o instanceof ContentToken){
			}else if(o instanceof EndTagToken){
			}
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	private WidgetDescription processElements(TagNode node,WidgetDescription parent){
		WidgetDescription root = null;
		if(parent == null){
			this.m_itemcounter = 0;
		}
		if(node.getName().equals("body")){
			System.out.println("Create the RootWidget ("+node.getName()+")");

			root = new WidgetDescription(node);
			root.setItemindex(this.m_itemcounter);
			this.m_itemcounter++;
		}else{
			System.out.println("Create Widget for "+node.getName());
			System.out.println("Attributes = "+node.getAttributes());
			root = new WidgetDescription(node);
			root.setItemindex(this.m_itemcounter);
			this.m_itemcounter++;
			if(parent != null){
				parent.addChildWidget(root);
			}
			if(node.getName().equals("table")){
				HashMap temp = statevariables;
				statevariables = new HashMap();
				statevariables.put("state", "1");
				
				WidgetDescription table = this.processTable(root,node);
				table.setContent(statevariables);
				statevariables = temp;
				return table;
			}else if(node.getName().equals("select")){
				HashMap temp = statevariables;
				statevariables = new HashMap();
				WidgetDescription select = this.processSelect(root,node);
				select.setContent(statevariables);
				statevariables = temp;
				return select;
			}
		}
		for(int i = 0;i < node.getChildren().size();i++){
			Object o = node.getChildren().get(i);
			if(o instanceof TagNode){
				TagNode child = (TagNode)o;
				this.processElements(child, root);
			}else if(o instanceof ContentToken){
				ContentToken child = (ContentToken)o;
				if(child.getContent().trim().length() > 0){
					System.out.println("Add content ("+child.getContent().trim()+") to widget.");
					WidgetDescription text = new WidgetDescription(child);
					text.setContent(child.getContent().trim());
					root.addChildWidget(text);
				}

			}else if(o instanceof EndTagToken){

			}
		}
		return root;
	}

	private WidgetDescription processSelect(WidgetDescription root, TagNode node) {
		
		return root;
	}

	@SuppressWarnings("unchecked")
	private WidgetDescription processTable(WidgetDescription root,TagNode node) {
		int state = Integer.parseInt((String)statevariables.get("state"));
		String name = node.getName();
		switch(state){
		case 1:
			System.out.println("Generate FlexTable");
			for(int i = 0; i < node.getChildTags().length;i++){
				statevariables.put("state", "2");
				this.processTable(root, node.getChildTags()[i]);
			}
			break;
		case 2:
			if(name.equalsIgnoreCase("tbody")){
				statevariables.put("state", "3");
			}else if(name.equalsIgnoreCase("thead")){
				statevariables.put("state", "4");
			}
			for(int i = 0; i < node.getChildTags().length;i++){
				this.processTable(root, node.getChildTags()[i]);
			}
			break;
		case 3:

		case 4:
			if(name.equalsIgnoreCase("tr")){
				statevariables.put("columnnumber", "0");
				if(statevariables.get("rownumber") == null){
					statevariables.put("rownumber", "0");
				}else{
					int row = Integer.parseInt((String)statevariables.get("rownumber"));
					row++;
					statevariables.put("rownumber", ""+row);
				}
				String style = node.getAttributeByName("class");
				if(style != null){
					statevariables.put("rowstyle."+statevariables.get("rownumber"), style);
				}
				for(int i = 0; i < node.getChildTags().length;i++){
					statevariables.put("state", "5");
					this.processTable(root,node.getChildTags()[i]);
				}
			}else{
				statevariables.put("state", "2");
			}
			break;
		case 5:
			if(name.equalsIgnoreCase("td")){
				int column = Integer.parseInt((String)statevariables.get("columnnumber"));
				int row = Integer.parseInt((String)statevariables.get("rownumber"));
				statevariables.put("columnnumber",""+column);
				String style = node.getAttributeByName("class");
				if(style != null){
					statevariables.put("cellclass."+row+"."+column, style);
				}
				String attrib = node.getAttributeByName("style");
				if(attrib != null){
					statevariables.put("cellstyle."+row+"."+column, attrib);
				}
				String width = node.getAttributeByName("width");
				if(width != null){
					statevariables.put("cellwidth."+row+"."+column, width);
				}
				WidgetDescription cell = this.processElements(node, root);
				statevariables.put("widget."+row+"."+column, cell);
				/*
				for(int i = 0; i < node.getChildren().size();i++){
					Object o = node.getChildren().get(i);
					if(o instanceof TagNode){
						WidgetDescription td = new WidgetDescription(node);
						WidgetDescription cell = this.processElements((TagNode)node.getChildren().get(i), root);
						Object obj = statevariables.get("widget."+row+"."+column);
						if(obj == null){
							statevariables.put("widget."+row+"."+column, td);
						}else{
							if(obj instanceof WidgetDescription){
								String wname = ((WidgetDescription)obj).getWidgetname();
								if(!wname.equalsIgnoreCase("flowpanel")){
									WidgetDescription div = new WidgetDescription("FlowPanel");
									
									root.addChildWidget(div);
									statevariables.put("widget."+row+"."+column, div);
									obj = div;
								}
								((WidgetDescription)obj).addChildWidget(cell);
							}
						}
					}else if(o instanceof ContentToken){
						if(((ContentToken)o).getContent().trim().length() > 0){
							WidgetDescription html = this.processElements(node, root);
							statevariables.put("widget."+row+"."+column, html);
						}
					}
				}
				*/
				column = Integer.parseInt((String)statevariables.get("columnnumber"));
				column++;
				statevariables.put("columnnumber", ""+column);
				statevariables.put("state", "4");
			}

			break;

		}
		return root;
	}

	private String getHTMLSRC() throws IOException {
		FileReader fw = new FileReader(this.m_source_file);
		StringBuffer buffer = new StringBuffer();
		char[] buf = new char[500];
		for(int i = fw.read(buf);i > -1;i = fw.read(buf)){
			buffer.append(buf, 0, i);
		}
		if(buffer.charAt(0) == 239){
			return buffer.toString().substring(3);
		}else{
			return buffer.toString();
		}
	}

	private void processArguments(String[] args) throws Exception {
		if(args.length < 4){
			throw new Exception("Not enough arguments.");
		}
		this.setSourceFile(args[0]);
		this.setClassName(args[1]);
		this.setPackage(args[2]);
		this.setDestinationFolder(args[3]);
	}

	private void setDestinationFolder(String string) throws Exception {
		
		File file = new File(string + System.getProperty("file.separator") + Strmanip.replacechar(this.m_package, '.', System.getProperty("file.separator").charAt(0)));
		this.m_destination_folder = file;
	}

	private void setPackage(String string) {
		this.m_package = string;
	}

	private void setClassName(String string) {
		this.m_classname = string.toUpperCase().charAt(0)+string.toLowerCase().substring(1)+"UI";
	}

	private void setSourceFile(String string) {
		File source = new File(string);
		this.m_source_file = source;
	}

	private void showUsage() {
		System.out.println("Usage: [source file] [name] [package] [destination]");
		System.out.println("  source file: The file name of the source html.");
		System.out.println("         name: The name of the class to be created.");
		System.out.println("      package: The package of the generated class.");
		System.out.println("  destination: The destination folder of the generated class.");
	}

}
